﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using Castle.MicroKernel.Registration;
using Castle.Windsor;

namespace DataScripter.Containers
{
    class WindsorContainer : IContainer
    {
        public string Name { get; private set; }

        private IContainer Parent
        {
            //get { return _iocContainer.Parent.Resolve<IContainer>(); }
            set { _iocContainer.Parent = ((WindsorContainer)value)._iocContainer; }
        }

        private readonly IWindsorContainer _iocContainer;
        private readonly List<IContainer> _childContainers = new List<IContainer>();

        public WindsorContainer(string name)
        {
            Name = name;
            _iocContainer = new Castle.Windsor.WindsorContainer();
        }

        public bool HasRegistration<T>()
        {
            return _iocContainer.Kernel.GetHandlers(typeof(T)).Length > 0;
        }

        public bool HasRegistration<T>(string name)
        {
            return _iocContainer.Kernel.HasComponent(name);
        }

        public T Resolve<T>()
        {
            if (HasRegistration<T>())
            {
                return _iocContainer.Resolve<T>();
            }
            foreach (IContainer child in _childContainers)
            {
                if (child.HasRegistration<T>())
                    return child.Resolve<T>();
            }
            return default(T);
        }

        public T Resolve<T>(string name)
        {
            if (HasRegistration<T>(name))
            {
                return _iocContainer.Resolve<T>(name);
            }
            foreach (IContainer child in _childContainers)
            {
                if (child.HasRegistration<T>(name))
                    return child.Resolve<T>(name);
            }
            return default(T);
        }

        public T Resolve<T>(string name, IDictionary dictionary)
        {
            if (HasRegistration<T>(name))
            {
                return _iocContainer.Resolve<T>(name, dictionary);
            }
            foreach (IContainer child in _childContainers)
            {
                if (child.HasRegistration<T>(name))
                    return child.Resolve<T>(name, dictionary);
            }
            return default(T);
        }

        public void RegisterType<T>(Type type)
        {
            Debug.WriteLine("Registering type " + type.Name);
            _iocContainer.Register(Component.For<T>().ImplementedBy(type));
        }

        public void RegisterType<T>(string name, Type type)
        {
            Debug.WriteLine("Registering instance " + name + " for " + type.Name);
            _iocContainer.Register(Component.For<T>().ImplementedBy(type).Named(name));
        }

        public void RegisterType(string name, Type type, Type interfaceType)
        {
            Debug.WriteLine("Registering instance " + name + " for " + type.Name);
            _iocContainer.Register(Component.For(interfaceType).ImplementedBy(type).Named(name));
        }


        public void RegisterType<T>(T instance)
        {
            Debug.WriteLine("Registering instance for " + instance.GetType().Name);
            _iocContainer.Register(Component.For<T>().Instance(instance));
        }

        public void RegisterType<T>(string name, T instance)
        {
            Debug.WriteLine("Registering instance " + name + " for " + instance.GetType().Name);
            _iocContainer.Register(Component.For<T>().Instance(instance).Named(name));
        }

        public IContainer CreateChildContainer(string name)
        {
            WindsorContainer childContainer = new WindsorContainer(name)
                                                  {
                                                      Parent = this
                                                  };
            _childContainers.Add(childContainer);
            _iocContainer.AddChildContainer(childContainer._iocContainer);
            childContainer.RegisterType<IContainer>(childContainer);
            return childContainer;
        }

    }
}
